package itsecurity.ui;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.util.Vector;

import iaik.asn1.ObjectID;
import iaik.asn1.structures.AlgorithmID;
import iaik.asn1.structures.Name;
import iaik.security.provider.IAIK;
import iaik.x509.V3Extension;
import iaik.x509.X509Certificate;
import iaik.x509.extensions.BasicConstraints;
import itsecurity.cert.CertificateFactory;
import itsecurity.cert.KeyManager;
import itsecurity.cert.MDBProvider;
import itsecurity.cert.SaveCertToFile;

/**
 * Class for creating certificates and signing them.
 *
 * Don't use the createCAcert -method if you don't have to! createClientCert-method 
 * gets the key from store file. 
 * Remember to get the store file via this version control! It's located in the top folder 
 * of the project. Here you should note that the project setting files in the top folder 
 * will collide with your own project settings if you get them too.
 *
 */
public class CreateCertUI {
	
	private X509Certificate BOBcert=null;
	private X509Certificate CAcert=null;
	private PrivateKey CAKey=null;
	
	CreateCertUI() {		
	}
	
	public void setCAKey(PrivateKey key) {
		CAKey = key;
	}
	
	public void createCACert() {
		Name subject = new Name();
	  subject.addRDN(ObjectID.country, "FIN");
	  subject.addRDN(ObjectID.locality, "Oulu");
	  subject.addRDN(ObjectID.organization ,"University of Oulu");
	  subject.addRDN(ObjectID.commonName ,"Circus Authorities");

	  Name issuer = new Name();
    issuer.addRDN(ObjectID.country, "FIN");
	  issuer.addRDN(ObjectID.locality, "Oulu");
    issuer.addRDN(ObjectID.organization ,"University of Oulu");
    issuer.addRDN(ObjectID.commonName ,"Circus Authorities");
	  
		System.out.println("\nGenerating key pair...");
		KeyPair kp = KeyManager.generateRSAKeyPair();
		System.out.println("CA private key is: "+kp.getPrivate().toString());
		System.out.print("\n\nPassword for CA key store is 'Bob'");
		File file=new File(KeyManager.KEYSTORE);
//		file.createNewFile();
   	try {
			Signature hash_rsa = Signature.getInstance("mdbWithRSAEncryption");
		} catch (NoSuchAlgorithmException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
   	AlgorithmID algorithm = new AlgorithmID("1.3.6.1.4.1.2706.4.1.2", "mdbWithRSAEncryption");
		//Certificate cert=null;
   	BasicConstraints bc = new BasicConstraints(true, 1);
		bc.setCa(true);
		
		Vector<V3Extension> extensions = new Vector<V3Extension>();
		extensions.addElement(bc);
		V3Extension[] v3 = new V3Extension[extensions.size()];
    extensions.copyInto(v3);
    
   	try {
			CAcert = CertificateFactory.createCertificate(subject, kp.getPublic(), issuer, 
					kp.getPrivate(), algorithm, 1, v3);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
//		PrivateKey caKey = KeyManager.getKeyPair("Circus authorities", "Bob".toCharArray(), file).getPrivate();
		Certificate[] certs = {CAcert};
		KeyManager.saveCert(subject.getName(), "Bob".toCharArray(), kp.getPrivate(), certs, file);
		SaveCertToFile.saveCertificate(CAcert, "CACert.cer");

		CAKey = kp.getPrivate();
	}

	public void createClientCert() throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		Name subject = new Name();
		System.out.print("\nName: ");
		String alias = in.readLine();
	  subject.addRDN(ObjectID.commonName ,alias);
		System.out.print("Country credentials (e.g. AT): ");
	  subject.addRDN(ObjectID.country, in.readLine());
		System.out.print("City: ");
	  subject.addRDN(ObjectID.locality, in.readLine());
		System.out.print("Organization: ");
	  subject.addRDN(ObjectID.organization ,in.readLine());
		System.out.print("Organizational unit: ");
	  subject.addRDN(ObjectID.organizationalUnit ,in.readLine());
	  
	  Name issuer = new Name();
    issuer.addRDN(ObjectID.country, "FIN");
    issuer.addRDN(ObjectID.locality, "Oulu");
    issuer.addRDN(ObjectID.organization ,"University of Oulu");
    issuer.addRDN(ObjectID.commonName ,"Circus Authorities");
	  
		System.out.println("\nGenerating key pair...");
		KeyPair kp = KeyManager.generateRSAKeyPair();
		System.out.println("Your public key is: "+kp.getPublic().toString());
		System.out.print("\n\nPassword for key store alias (your name):");
		char [] password = in.readLine().toCharArray();
		File file=new File(KeyManager.KEYSTORE);
		//file.createNewFile();
   	AlgorithmID algorithm = new AlgorithmID("1.3.6.1.4.1.2706.4.1.2", "mdbWithRSAEncryption");
   	CAKey = KeyManager.getKeyPair("Circus Authorities", "Bob".toCharArray(), file).getPrivate();
   	
   	try {
			BOBcert = CertificateFactory.createCertificate(subject, kp.getPublic(), issuer, 
					CAKey, algorithm, 2, null);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Certificate[] certs = {BOBcert};
		SaveCertToFile.saveCertificate(BOBcert, "ClientCert.cer");
		KeyManager.saveCert(alias, password, kp.getPrivate(), certs, file);
		
	}
	
	public void printMenu() {
		System.out.println("\n"+ //1 - Create new CA certificate\n
				"1 - Create new client certificate\n"+
				"\n 0 - Quit\n\n> ");
	}

	public static void main(String [] args) {
		try {
	    Security.insertProviderAt(new IAIK(), 2);
	    Security.insertProviderAt(new MDBProvider(), 3);
	  } catch( Throwable e ) {
	    //
	  }
		FileOutputStream fos=null;
		try {
			  CreateCertUI ui = new CreateCertUI();
		    ui.printMenu();
		    int choice = System.in.read();
			  while (choice != 0) {
			    switch (choice) {
			    case 0:
			    	break;
			    case 1:
			    	ui.createClientCert();
			    	break;
			    default:
			    	break;
			    }
				  ui.printMenu();
			    choice = System.in.read();
				}
		} catch (Exception e) { 
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}
